package dao

import (
	"errors"
	"fmt"
	"math"
	"sort"
	"time"
	"user_srv/basic/config"
	"user_srv/handler/models"
	"user_srv/untils"
)

//// UpdateUserLocation 更新用户位置信息（基础版本）
//func UpdateUserLocation(userId uint64, latitude, longitude float64) error {
//	return UpdateUserLocationEnhanced(userId, latitude, longitude, 0, "unknown", "", "", "", "", "")
//}

// UpdateUserLocationEnhanced 增强的位置更新（支持完整字段）
func UpdateUserLocationEnhanced(userId uint64, latitude, longitude, accuracy float64, source, address, city, district, province string) error {
	// 验证纬度范围 -90 到 90
	if latitude < -90 || latitude > 90 {
		return errors.New("纬度范围必须在 -90 到 90 之间")
	}

	// 验证经度范围 -180 到 180
	if longitude < -180 || longitude > 180 {
		return errors.New("经度范围必须在 -180 到 180 之间")
	}

	// 更新用户位置
	now := time.Now()
	err := config.DB.Model(&models.User{}).
		Where("id = ?", userId).
		Updates(map[string]interface{}{
			"latitude":            latitude,
			"longitude":           longitude,
			"location_accuracy":   accuracy,
			"location_source":     source,
			"location_address":    address,
			"location_city":       city,
			"location_district":   district,
			"location_province":   province,
			"location_updated_at": now,
		}).Error

	if err != nil {
		return errors.New("更新位置失败：" + err.Error())
	}

	// 记录位置历史
	history := models.LocationHistory{
		UserId:    userId,
		Latitude:  latitude,
		Longitude: longitude,
		Accuracy:  accuracy,
		Source:    source,
		Address:   address,
		City:      city,
		District:  district,
		Province:  province,
		CreatedAt: now,
	}

	err = history.Create()
	if err != nil {
		// 历史记录失败不影响主功能
		// 记录位置历史失败，但不影响主流程
		// fmt.Printf("记录位置历史失败: %v\n", err)
	}

	return nil
}

// GetNearbyUsers 获取附近的用户
// 性能优化建议：
// 1. 可以添加Redis缓存，缓存热点区域的用户列表
// 2. 可以添加空间索引（如R-tree）提高查询效率
// 3. 可以分页查询，避免一次性返回大量数据
func GetNearbyUsers(userId uint64, radius float64, limit int) ([]models.User, error) {
	// 获取当前用户信息
	var user models.User
	user.Id = userId
	err := user.GetById()
	if err != nil {
		return nil, errors.New("获取用户信息失败：" + err.Error())
	}

	// 检查用户是否有位置信息
	if user.Latitude == nil || user.Longitude == nil {
		return nil, errors.New("请先更新您的位置信息")
	}

	// 设置默认值
	if radius <= 0 {
		radius = 10 // 默认10km
	}
	if radius > 50 {
		radius = 50 // 最大50km
	}
	if limit <= 0 {
		limit = 20
	}

	// 计算大致的经纬度范围（粗筛）
	// 纬度1度约等于111km
	latRange := radius / 111.0
	// 经度1度在不同纬度处的距离不同，这里用cos(纬度)来修正
	lonRange := radius / (111.0 * math.Cos(*user.Latitude*math.Pi/180.0))

	// 查询矩形范围内的用户（添加索引优化）
	var candidates []models.User
	err = config.DB.Where("id != ? AND status = 1", userId).
		Where("latitude IS NOT NULL AND longitude IS NOT NULL").
		Where("latitude BETWEEN ? AND ?", *user.Latitude-latRange, *user.Latitude+latRange).
		Where("longitude BETWEEN ? AND ?", *user.Longitude-lonRange, *user.Longitude+lonRange).
		Order("id"). // 添加排序，利用索引
		Find(&candidates).Error

	if err != nil {
		return nil, errors.New("查询附近用户失败：" + err.Error())
	}

	// 精确计算距离并过滤
	type UserWithDistance struct {
		User     models.User
		Distance float64
	}

	var usersWithDistance []UserWithDistance
	for _, candidate := range candidates {
		if candidate.Latitude == nil || candidate.Longitude == nil {
			continue
		}

		// 使用工具函数计算精确距离
		distance := untils.CalculateDistance(*user.Latitude, *user.Longitude, *candidate.Latitude, *candidate.Longitude)

		// 只保留在半径范围内的用户
		if distance <= radius {
			usersWithDistance = append(usersWithDistance, UserWithDistance{
				User:     candidate,
				Distance: distance,
			})
		}
	}

	// 按距离排序（使用快速排序）
	sort.Slice(usersWithDistance, func(i, j int) bool {
		return usersWithDistance[i].Distance < usersWithDistance[j].Distance
	})

	// 限制返回数量
	if len(usersWithDistance) > limit {
		usersWithDistance = usersWithDistance[:limit]
	}

	// 提取用户列表
	var nearbyUsers []models.User
	for _, item := range usersWithDistance {
		nearbyUsers = append(nearbyUsers, item.User)
	}

	return nearbyUsers, nil
}

// GetLocationHistory 获取用户位置历史
func GetLocationHistory(userId uint64, limit int) ([]models.LocationHistory, error) {
	var history models.LocationHistory
	return history.GetByUserId(userId, limit)
}

// GetUsersInCity 获取同城用户
func GetUsersInCity(userId uint64, city string, limit int) ([]models.User, error) {
	var users []models.User

	err := config.DB.Where("id != ? AND location_city = ? AND status = 1", userId, city).
		Order("location_updated_at DESC").
		Limit(limit).
		Find(&users).Error

	return users, err
}

// POI 兴趣点结构体
type POI struct {
	Id       uint64  `json:"id"`
	Name     string  `json:"name"`
	Type     string  `json:"type"`
	Address  string  `json:"address"`
	Location string  `json:"location"`
	Distance float64 `json:"distance"`
}

// GetNearbyPOI 获取附近兴趣点
// 根据经纬度和半径获取附近的POI（兴趣点）
func GetNearbyPOI(latitude, longitude float64, radius int, keyword string) ([]POI, error) {
	// 这里应该调用第三方地图API（如高德、百度、腾讯地图）
	// 由于没有真实的API key，这里返回模拟数据

	// 模拟POI数据
	pois := []POI{
		{
			Id:       1,
			Name:     "星巴克咖啡",
			Type:     "餐饮",
			Address:  "北京市朝阳区三里屯",
			Location: fmt.Sprintf("%.6f,%.6f", latitude+0.001, longitude+0.001),
			Distance: 150.5,
		},
		{
			Id:       2,
			Name:     "万达广场",
			Type:     "购物",
			Address:  "北京市朝阳区建国路",
			Location: fmt.Sprintf("%.6f,%.6f", latitude+0.002, longitude+0.002),
			Distance: 300.8,
		},
		{
			Id:       3,
			Name:     "地铁站",
			Type:     "交通",
			Address:  "北京市朝阳区国贸",
			Location: fmt.Sprintf("%.6f,%.6f", latitude-0.001, longitude+0.001),
			Distance: 200.3,
		},
	}

	// 如果有关键词，进行过滤
	if keyword != "" {
		var filteredPois []POI
		for _, poi := range pois {
			if poi.Name == keyword || poi.Type == keyword {
				filteredPois = append(filteredPois, poi)
			}
		}
		return filteredPois, nil
	}

	return pois, nil
}

// CreateGeoFence 创建地理围栏
func CreateGeoFence(userId uint64, name string, centerLat, centerLng, radius float64) error {
	fence := models.GeoFence{
		UserId:    userId,
		Name:      name,
		CenterLat: centerLat,
		CenterLng: centerLng,
		Radius:    radius,
		Status:    1,
		CreatedAt: time.Now(),
	}

	return fence.Create()
}

// GetUserGeoFences 获取用户的地理围栏
func GetUserGeoFences(userId uint64) ([]models.GeoFence, error) {
	var fence models.GeoFence
	return fence.GetByUserId(userId)
}

// CheckGeoFence 检查用户是否在围栏内
func CheckGeoFence(userId uint64, lat, lng float64) ([]models.GeoFence, error) {
	fences, err := GetUserGeoFences(userId)
	if err != nil {
		return nil, err
	}

	var result []models.GeoFence
	for _, fence := range fences {
		distance := untils.CalculateDistance(lat, lng, fence.CenterLat, fence.CenterLng)
		if distance*1000 <= fence.Radius { // 转换为米
			result = append(result, fence)
		}
	}

	return result, nil
}

// GetLocationStats 获取用户位置统计
func GetLocationStats(userId uint64) (*models.LocationStats, error) {
	var stats models.LocationStats
	err := stats.GetByUserId(userId)
	if err != nil {
		// 如果不存在，创建新的统计记录
		stats = models.LocationStats{
			UserId: userId,
		}
		err = stats.Create()
		if err != nil {
			return nil, err
		}
	}
	return &stats, nil
}

// UpdateLocationStats 更新位置统计
func UpdateLocationStats(userId uint64) error {
	stats, err := GetLocationStats(userId)
	if err != nil {
		return err
	}

	// 统计总位置数
	var totalCount int64
	err = config.DB.Model(&models.LocationHistory{}).Where("user_id = ?", userId).Count(&totalCount).Error
	if err != nil {
		return err
	}

	// 统计活跃天数
	var activeDays int64
	err = config.DB.Raw("SELECT COUNT(DISTINCT DATE(created_at)) FROM location_history WHERE user_id = ?", userId).Scan(&activeDays).Error
	if err != nil {
		return err
	}

	// 计算平均精度
	var avgAccuracy float64
	err = config.DB.Raw("SELECT AVG(accuracy) FROM location_history WHERE user_id = ? AND accuracy > 0", userId).Scan(&avgAccuracy).Error
	if err != nil {
		avgAccuracy = 0
	}

	// 更新统计信息
	stats.TotalLocations = int(totalCount)
	stats.ActiveDays = int(activeDays)
	stats.AverageAccuracy = avgAccuracy
	stats.LastActiveDate = time.Now()

	return stats.Update()
}

// GetLocationHeatmap 获取位置热力图数据  生成位置热力图数据
func GetLocationHeatmap(bounds Bounds, zoom int) ([]HeatmapPoint, error) {
	var points []HeatmapPoint

	// 根据地图边界和缩放级别获取热力图数据
	err := config.DB.Raw(`
		SELECT 
			latitude, 
			longitude, 
			COUNT(*) as weight
		FROM user 
		WHERE latitude BETWEEN ? AND ? 
		AND longitude BETWEEN ? AND ?
		AND latitude IS NOT NULL 
		AND longitude IS NOT NULL
		GROUP BY ROUND(latitude, ?), ROUND(longitude, ?)
	`, bounds.South, bounds.North, bounds.West, bounds.East, zoom, zoom).
		Scan(&points).Error
	//根据地图的边界范围和缩放级别，从数据库中查询用户位置数据，并生成用于绘制热力图的数据点。
	// 每个数据点包含纬度、经度和权重（位置出现次数）。
	return points, err
}

// Bounds 地图边界
type Bounds struct {
	North float64 `json:"north"`
	South float64 `json:"south"`
	East  float64 `json:"east"`
	West  float64 `json:"west"`
}

// HeatmapPoint 热力图点
type HeatmapPoint struct {
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
	Weight    int     `json:"weight"`
}

// RecordLocationEvent 记录位置事件
func RecordLocationEvent(userId uint64, eventType string, lat, lng float64, address, data string) error {
	event := models.LocationEvent{
		UserId:    userId,
		EventType: eventType,
		Latitude:  lat,
		Longitude: lng,
		Address:   address,
		Data:      data,
		CreatedAt: time.Now(),
	}

	return event.Create()
}

// GetLocationEvents 获取位置事件
func GetLocationEvents(userId uint64, eventType string, limit int) ([]models.LocationEvent, error) {
	var event models.LocationEvent
	return event.GetByUserId(userId, eventType, limit)
}
